/**
 * Copyright 2008 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kiff.entity;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.Version;

import kiff.dao.UserDAO;
import kiff.security.Principal;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * User Entity.
 * @author Adam
 * @version $Id: User.java 73 2008-12-02 06:28:25Z a.ruggles $
 */
@Entity @Table(name = "users")
@NamedQueries({
	@NamedQuery(name = UserDAO.GET_BY_USERNAME, query = "select u from User u where u.username = :username")
})
public class User implements CoreEntity<Integer>, UpdateAware<User>, TrackAware,  Comparable<User> {
	/**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = -6130176739188761579L;

	/**
     * Is the user account active.
     */
    private Boolean active;

    /**
     * Administrator flag.
     */
    private boolean administrator = false;

    /**
     * The Avatar File Path.
     */
    private String avatar;

    /**
     * The date and time the post was created.
     */
    private Date created;

    /**
     * The user that created the user record.
     */
    private User creator;

    /**
     * The Email address.
     */
    private String email;

    /**
     * The unique identifier.
     */
    private Integer id;

    /**
     * Moderator flag.
     */
    private boolean moderator = false;

    /**
     * The date and time the post was last updated.
     */
    private Date modified;

    /**
     * Password.
     */
    private String password;

    /**
     * The Security Roles that the user belongs to.
     */
    private Set<Principal> roles = new HashSet<Principal>();

    /**
     * A Seed value used to salt the user's password.
     */
    private Long seed;

    /**
     * The Username for this user.
     */
    private String username;

    /**
     * The version for optimistic concurrency control.
     */
    private Integer version;

	/**
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	public int compareTo(final User user) {
		if (this.username == null || user == null || user.getUsername() == null) {
			return -1;
		}
		return this.username.compareTo(user.getUsername());
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof User)) {
			return false;
		}
		User rhs = (User) obj;
		return new EqualsBuilder()
			.append(username, rhs.getUsername())
			.isEquals();
	}

    /**
	 * Returns the active status.
	 * @return the active status.
	 */
	@Basic(optional = false)
	public Boolean getActive() {
		return active;
	}

	/**
	 * Retursn the avatar path.
	 * @return the avatar path.
	 */
	public String getAvatar() {
		return avatar;
	}

	/**
	 * Returns the created date.
	 * @return the created date.
	 */
	@Basic(optional = false) @Temporal(TemporalType.TIMESTAMP)
	public Date getCreated() {
		return created;
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.entity.TrackAware#getCreator()
	 */
	@ManyToOne(optional = true, fetch = FetchType.LAZY) @JoinColumn(name = "creator_id")
	public User getCreator() {
		return creator;
	}

	/**
	 * Returns the email address.
	 * @return the email address.
	 */
	@Column(nullable = false, unique = true)
	public String getEmail() {
		return email;
	}

	/**
	 * @see kiff.entity.CoreEntity#getId()
	 */
	@Id @GeneratedValue(strategy = GenerationType.AUTO)
	public Integer getId() {
		return id;
	}

    /**
	 * Returns the modified date.
	 * @return the modified date.
	 */
	@Basic(optional = false) @Temporal(TemporalType.TIMESTAMP)
	public Date getModified() {
		return modified;
	}

	/**
	 * Returns the password.
	 * @return the password.
	 */
	@Column(length = 40, nullable = false)
	public String getPassword() {
		return password;
	}

	/**
	 * The roles that are assigned to the user.
	 * @return the roles
	 */
	@ManyToMany(fetch = FetchType.LAZY, targetEntity = Role.class)
	@JoinTable(name = "users_roles",
			joinColumns = @JoinColumn(name = "user_id"),
			inverseJoinColumns = @JoinColumn(name = "role_id"))
	@org.hibernate.annotations.Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
	public Set<Principal> getRoles() {
		return roles;
	}

	/**
	 * Returns seed.
	 * @return the seed.
	 */
	@Basic(optional = false)
	public Long getSeed() {
		return seed;
	}

	/**
	 * Returns the username.
	 * @return the username.
	 */
	@Column(length = 50, nullable = false, unique = true)
	public String getUsername() {
		return username;
	}

	/**
	 * Returns the version.
	 * @return the version to return.
	 */
	@Version
	public Integer getVersion() {
		return version;
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return new HashCodeBuilder(37, 11)
			.append(username)
			.toHashCode();
	}

	/**
	 * Returns administrator.
	 * @return the administrator.
	 */
	@Transient
	public boolean isAdministrator() {
		return administrator;
	}

	/**
	 * Returns moderator.
	 * @return the moderator.
	 */
	@Transient
	public boolean isModerator() {
		return moderator;
	}

	/**
	 * Sets the active status.
	 * @param active the active status to set.
	 */
	public void setActive(final Boolean active) {
		this.active = active;
	}

	/**
	 * Sets administrator.
	 * @param administrator the administrator to set.
	 */
	public void setAdministrator(final boolean administrator) {
		this.administrator = administrator;
	}

	/**
	 * Sets the avatar image path.
	 * @param avatar the avatar path to set.
	 */
	public void setAvatar(final String avatar) {
		this.avatar = avatar;
	}

	/**
	 * @see kiff.entity.TrackAware#setCreated(java.util.Date)
	 */
	public void setCreated(final Date created) {
		this.created = created;
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.entity.TrackAware#setCreator(kiff.entity.User)
	 */
	public void setCreator(final User creator) {
		this.creator = creator;
	}

	/**
	 * Sets the email.
	 * @param email the email to set.
	 */
	public void setEmail(final String email) {
		this.email = email;
	}

	/**
	 * @see kiff.entity.CoreEntity#setId(java.io.Serializable)
	 */
	public void setId(final Integer id) {
		this.id = id;
	}

	/**
	 * Sets moderator.
	 * @param moderator the moderator to set.
	 */
	public void setModerator(final boolean moderator) {
		this.moderator = moderator;
	}

	/**
	 * @see kiff.entity.TrackAware#setModified(java.util.Date)
	 */
	public void setModified(final Date modified) {
		this.modified = modified;
	}

	/**
	 * Sets the password.
	 * @param password the password to set.
	 */
	public void setPassword(final String password) {
		this.password = password;
	}

	/**
	 * The roles to assign to the user.
	 * @param roles the roles to set.
	 */
	public void setRoles(final Set<Principal> roles) {
		this.roles = roles;
	}

	/**
	 * Sets seed.
	 * @param seed the seed to set.
	 */
	public void setSeed(final Long seed) {
		this.seed = seed;
	}

	/**
	 * Sets the username.
	 * @param username the username to set.
	 */
	public void setUsername(final String username) {
		this.username = username;
	}

	/**
	 * Sets the version.
	 * @param version the version to set.
	 */
	public void setVersion(final Integer version) {
		this.version = version;
	}

	/**
	 * @see java.lang.Object#toString()
     */
	public String toString() {
		return new ToStringBuilder(this)
			.append("id", id)
			.append("username", username)
			.append("created", created)
			.append("modified", modified)
			.append("active", active)
			.append("email", email)
			.append("username", username)
			.toString();
	}

	/**
	 * @see kiff.entity.UpdateAware#update(java.lang.Object)
	 */
	public void update(final User entity) {
		if (entity.active != null) {
			this.active = entity.active;
		}
		if (entity.avatar != null) {
			this.avatar = entity.avatar;
		}
		if (entity.getCreator() != null) {
			this.creator = entity.getCreator();
		}
		if (entity.modified != null) {
			this.modified = entity.modified;
		}
		if (entity.email != null) {
			this.email = entity.email;
		}
		if (entity.password != null) {
			this.password = entity.password;
		}
		if (entity.roles != null) {
			this.roles = entity.roles;
		}
		if (entity.username != null) {
			this.username = entity.username;
		}
	}

}
